package com.yingxin.yx.framework.commons.helper.loop;

import com.yingxin.yx.framework.commons.helper.DecimalHelper;
import com.yingxin.yx.framework.commons.helper.loop.setter.LoopBigDecimalSetter;
import com.yingxin.yx.framework.commons.helper.loop.setter.LoopIntegerSetter;
import com.yingxin.yx.framework.commons.helper.loop.setter.LoopSetter;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

public class LoopAddHelper {

    /**
     * 列合计
     *
     * @param list
     * @param totalRow
     * @param getterList
     * @param setterList
     * @param <T>
     * @param <R>
     */
    public static <T, R> void columnTotal(List<T> list, T totalRow, List<Function<T, R>> getterList, List<LoopSetter<T>> setterList) {
        assert getterList.size() == setterList.size();
        if (list != null) {
            for (T t : list) {
                for (int i = 0; i < getterList.size(); i++) {
                    Function<T, R> getter = getterList.get(i);
                    Object val = getter.apply(t);
                    if (val == null) {
                        continue;
                    }
                    if (val instanceof BigDecimal) {
                        BigDecimal total = (getter.apply(totalRow) == null ? BigDecimal.ZERO : (BigDecimal) getter.apply(totalRow));
                        total = DecimalHelper.add(total, (BigDecimal) val);
                        setterList.get(i).apply(totalRow, total);
                    } else if (val instanceof Integer) {
                        int total = (getter.apply(totalRow) == null ? 0 : (Integer) getter.apply(totalRow));
                        total = total + (Integer) val;
                        setterList.get(i).apply(totalRow, total);
                    } else if (val instanceof Long) {
                        long total = (getter.apply(totalRow) == null ? 0 : (Long) getter.apply(totalRow));
                        total = total + (Long) val;
                        setterList.get(i).apply(totalRow, total);
                    }
                }
            }
        }
    }

    /**
     * 列合计
     */
    public static <T> T decimalColumnTotal(List<T> list, T totalRow, List<Function<T, BigDecimal>> getterList, List<LoopBigDecimalSetter<T>> setterList) {
        assert getterList.size() == setterList.size();
        if (list != null) {
            for (T t : list) {
                for (int i = 0; i < getterList.size(); i++) {
                    Function<T, BigDecimal> getter = getterList.get(i);
                    BigDecimal val = getterBigDecimal(t, getter);
                    BigDecimal total = getterBigDecimal(totalRow, getter);
                    total = DecimalHelper.add(total, val);
                    setterList.get(i).apply(totalRow, total);
                }
            }
        }
        return totalRow;
    }

    /**
     * 列合计
     *
     * @param list
     * @param getter
     * @param <T>
     * @return
     */
    public static <T> BigDecimal decimalColumnTotal(List<T> list, Function<T, BigDecimal> getter) {
        BigDecimal total = BigDecimal.ZERO;
        if (list != null) {
            for (T t : list) {
                BigDecimal val = getterBigDecimal(t, getter);
                total = DecimalHelper.add(total, val);
            }
        }
        return total;
    }

    public static <T> BigDecimal decimalColumnTotal(Map<String, T> map, Function<T, BigDecimal> getter) {
        BigDecimal total = BigDecimal.ZERO;
        if (map != null) {
            for (T t : map.values()) {
                BigDecimal val = getterBigDecimal(t, getter);
                total = DecimalHelper.add(total, val);
            }
        }
        return total;
    }


    /**
     * 列合计
     *
     * @param list
     * @param totalRow
     * @param getterList
     * @param setterList
     * @param <T>
     * @return
     */
    public static <T> T intColumnTotal(List<T> list, T totalRow, List<Function<T, Integer>> getterList, List<LoopIntegerSetter<T>> setterList) {
        assert getterList.size() == setterList.size();
        if (list != null) {
            for (T t : list) {
                for (int i = 0; i < getterList.size(); i++) {
                    Function<T, Integer> getter = getterList.get(i);
                    int val = (getter.apply(t) == null ? 0 : getter.apply(t));
                    int total = (getter.apply(totalRow) == null ? 0 : getter.apply(totalRow));
                    total = total + val;
                    setterList.get(i).apply(totalRow, total);
                }
            }
        }
        return totalRow;
    }

    /**
     * 列合计
     *
     * @param list
     * @param getter
     * @param <T>
     * @return
     */
    public static <T> Integer intColumnTotal(List<T> list, Function<T, Integer> getter) {
        int total = 0;
        if (list != null) {
            for (T t : list) {
                int val = (getter.apply(t) == null ? 0 : getter.apply(t));
                total = total + val;
            }
        }
        return total;
    }


    public static <T> Long longColumnTotal(List<T> list, Function<T, Long> getter) {
        long total = 0L;
        if (list != null) {
            for (T t : list) {
                long val = (getter.apply(t) == null ? 0L : getter.apply(t));
                total = total + val;
            }
        }
        return total;
    }

    /**
     * 行合计
     */
    public static <T> void decimalRowTotal(List<T> list, List<Function<T, BigDecimal>> getterList, LoopBigDecimalSetter<T> setter) {
        if (list != null) {
            for (T t : list) {
                BigDecimal total = BigDecimal.ZERO;
                for (Function<T, BigDecimal> getter : getterList) {
                    BigDecimal val = getterBigDecimal(t, getter);
                    total = DecimalHelper.add(total, val);
                }
                setter.apply(t, total);
            }
        }
    }

    public static <T> void decimalRowTotal(T t, List<Function<T, BigDecimal>> getterList, LoopBigDecimalSetter<T> setter) {
        BigDecimal total = BigDecimal.ZERO;
        for (Function<T, BigDecimal> getter : getterList) {
            BigDecimal val = getterBigDecimal(t, getter);
            total = DecimalHelper.add(total, val);
        }
        setter.apply(t, total);
    }

    private static <T> BigDecimal getterBigDecimal(T t, Function<T, BigDecimal> getter) {
        return (getter.apply(t) == null ? BigDecimal.ZERO : getter.apply(t));
    }

}
